package com.rstrulak.constant;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.hibernate.Criteria;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Restrictions;

public abstract class GenericFilter {
    /**
     * Array for {@link FilterField}.
     */
    private List<FilterField<?>> filterFields;

    /**
     * Constructor.
     */
    public GenericFilter() {
        this.filterFields = new ArrayList<FilterField<?>>();
    }

    /**
     * Adds {@link FilterField} to internal list.
     * 
     * @param filerField the {@link FilterField} to add
     * @return the added {@link FilterField}
     */
    public FilterField<?> addFilterField(FilterField<?> filerField) {
        filterFields.add(filerField);
        return filerField;
    }

    /**
     * Getter for filterFields.
     * 
     * @return the filterFields
     */
    public List<FilterField<?>> getFilterFields() {
        return filterFields;
    }

    /**
     * Adds {@link Restrictions} to {@link Criteria} object base on
     * {@link FilterField} stored in object.
     * 
     * @param criteria the {@link Criteria} to add {@link Restrictions}
     */
    public void addRestrictionFromFilterFields(DetachedCriteria criteria) {
        if (criteria != null && this.filterFields != null && !this.filterFields.isEmpty()) {
            for (FilterField<?> field : this.filterFields) {
                String fieldName = field.getFieldName();
                Object value = field.getValue();
                MatchMode matchMode = field.getMatchMode();
                if (value instanceof String && StringUtils.isEmpty((String) value)) {
                    value = null;
                }
                if (value != null) {
                    switch (field.getComparisonType()) {
                    case EQUAL:
                        criteria.add(Restrictions.eq(fieldName, value));
                        break;
                    case LIKE:
                        criteria.add(Restrictions.like(fieldName, (String) value, matchMode));
                        break;
                    case LIKE_CASE_INSENSITIVE:
                        criteria.add(Restrictions.ilike(fieldName, (String) value, matchMode));
                        break;
                    case GREATER:
                        criteria.add(Restrictions.gt(fieldName, value));
                        break;
                    case GREATER_EQUAL:
                        criteria.add(Restrictions.ge(fieldName, value));
                        break;
                    case LESS:
                        criteria.add(Restrictions.lt(fieldName, value));
                        break;
                    case LESS_EQUAL:
                        criteria.add(Restrictions.le(fieldName, value));
                        break;
                    case IN:
                        criteria.add(Restrictions.in(fieldName, ((Collection<?>) value).toArray()));
                        break;
                    default:
                        criteria.add(Restrictions.eq(fieldName, value));

                    }
                }
            }
        }
    }

    /**
     * Adds {@link Restrictions} to {@link Criteria} object base on
     * {@link FilterField} stored in object.
     * 
     * @param criteria the {@link Criteria} to add {@link Restrictions}
     */
    public void addRestrictionFromFilterFields(Criteria criteria) {
        if (criteria != null && this.filterFields != null && !this.filterFields.isEmpty()) {
            for (FilterField<?> field : this.filterFields) {
                String fieldName = field.getFieldName();
                Object value = field.getValue();
                MatchMode matchMode = field.getMatchMode();
                if (value instanceof String && StringUtils.isEmpty((String) value)) {
                    value = null;
                }
                if (value != null) {
                    switch (field.getComparisonType()) {
                    case EQUAL:
                        criteria.add(Restrictions.eq(fieldName, value));
                        break;
                    case LIKE:
                        criteria.add(Restrictions.like(fieldName, (String) value, matchMode));
                        break;
                    case LIKE_CASE_INSENSITIVE:
                        criteria.add(Restrictions.ilike(fieldName, (String) value, matchMode));
                        break;
                    case GREATER:
                        criteria.add(Restrictions.gt(fieldName, value));
                        break;
                    case GREATER_EQUAL:
                        criteria.add(Restrictions.ge(fieldName, value));
                        break;
                    case LESS:
                        criteria.add(Restrictions.lt(fieldName, value));
                        break;
                    case LESS_EQUAL:
                        criteria.add(Restrictions.le(fieldName, value));
                        break;
                    case IN:
                        criteria.add(Restrictions.in(fieldName, ((Collection<?>) value).toArray()));
                        break;
                    default:
                        criteria.add(Restrictions.eq(fieldName, value));

                    }
                }
            }
        }
    }
}
